
package com.comtop.lcam.fwms.managementkey.socket;

import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.nio.charset.StandardCharsets;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.comtop.lcam.fwms.managementkey.dto.EslcsKeyDTO;
import com.comtop.lcam.fwms.managementkey.dto.EslcsLockLogDTO;
import com.comtop.lcam.fwms.managementkey.facade.internal.EslcsKeyFacade;
import com.comtop.lcam.fwms.managementkey.facade.internal.EslcsLockLogFacade;
import com.comtop.sproc.core.base.util.SprocApplicationContextUtil;

/**
 * 服务端处理通道
 */
@ChannelHandler.Sharable
public class EslcsSocketHandler extends ChannelInboundHandlerAdapter {
    
    static private ConcurrentMap<String, EslcsSoketKeyInfo> keyMap = new ConcurrentHashMap<>();
    
    static private int count_89 = 0;
    
    /** 异常输出 */
    private static final Logger LOGGER = LoggerFactory.getLogger(EslcsSocketHandler.class);
    
    /** 开锁日志管理服务 */
    @Resource
    private EslcsLockLogFacade eslcsLockLogFacade = SprocApplicationContextUtil.getContext().getBean(EslcsLockLogFacade.class);
    
    /** 钥匙管理服务 */
    @Resource
    private EslcsKeyFacade eslcsKeyFacade = SprocApplicationContextUtil.getContext().getBean(EslcsKeyFacade.class);
    
    /***
     * 这个方法会在发生异常时触发
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
        LOGGER.error("--------Netty Exception ExceptionCaught :" + ctx.channel().id().asShortText() + " " + cause.getMessage()
            + "=======================");
        ctx.close();
    }
    
    /**
     * 连接断开处理事件
     */
    @Override
    public void channelInactive(ChannelHandlerContext ctx) {
        count_89 = 0;
        LOGGER.error("--------Netty Disconnect Client IP is :" + ctx.channel().id().asShortText() + " " + ctx.channel().remoteAddress() + "--------");
        ctx.close();
    }
    
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        LOGGER.error("--------Netty Client IP is :" + ctx.channel().remoteAddress() + "--------");
        String str = EslcsSocketConstants.SERVICE_SEND_0X70
            + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(EslcsSocketConstants.SERVICE_SEND_0X70)) + EslcsSocketConstants.Constants_endIndex;
        ctx.channel().writeAndFlush(EslcsSocketHexUtil.HexToByteArr(str));
        LOGGER.error("--------Netty Service " + ctx.channel().id().asShortText() + " " + str + "---------");
    }
    
    /**
     * 功能：读取服务器发送过来的信息NB-BlueTLock V1.0 L18.1119.1 861964040627338 89860436101880120304
     */
    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        String channelId = ctx.channel().id().asShortText();
        ByteBuf buf = (ByteBuf) msg;
        byte[] con = new byte[buf.readableBytes()];
        buf.readBytes(con);
        String str = EslcsSocketHexUtil.byteArrayToHex(con);
        LOGGER.error("--------Netty Client " + ctx.channel().id().asShortText() + " " + str + "---------");
        EslcsSoketObject eslcsSoketObject = new EslcsSoketObject();
        String cmdValue = str.substring(4, 6);
        String cmdValueId = str.substring(6, 14);
        String eEffData = str.substring(16, str.length() - 4);
        String effDataLength = str.substring(2, 4);
        String xorCheck = str.substring(str.length() - 4, str.length() - 2);
        // 进行异或校验
        String getXor = EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(str.substring(0, str.length() - 4)));
        if (xorCheck.toUpperCase().equals(getXor.toUpperCase())) {
            eslcsSoketObject.setBeginIndex(str.substring(0, 2));
            eslcsSoketObject.setEffDataLength(effDataLength);
            eslcsSoketObject.setCmdValue(cmdValue);
            eslcsSoketObject.setCmdValueId(cmdValueId);
            eslcsSoketObject.setResponse(str.substring(14, 16));
            eslcsSoketObject.setEffData(eEffData);
            eslcsSoketObject.setXorCheck(xorCheck);
            eslcsSoketObject.setEndIndex(str.substring(str.length() - 2, str.length()));
            
            if (EslcsSocketConstants.Constants_70.equals(cmdValue)) {
                EslcsSoketKeyInfo eslcsSoketKeyInfo = new EslcsSoketKeyInfo();
                eslcsSoketKeyInfo.setChannelId(channelId);
                eslcsSoketKeyInfo.setKey(new String(EslcsSocketHexUtil.HexToByteArr(eEffData)));
                eslcsSoketKeyInfo.setHex(str);
                eslcsSoketKeyInfo.setUpdate(new Date());
                keyMap.put(channelId, eslcsSoketKeyInfo);
            } else if (EslcsSocketConstants.Constants_25.equals(cmdValue)) {
                String msg_25 = "aa0125000000010100";
                ctx.channel().writeAndFlush(
                    EslcsSocketHexUtil.HexToByteArr(msg_25 + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_25))
                        + EslcsSocketConstants.Constants_endIndex));
                LOGGER.error("--------Netty Service " + ctx.channel().id().asShortText() + " " + msg_25
                    + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_25)) + EslcsSocketConstants.Constants_endIndex + "---------");
                Thread.sleep(500);
                // 继续在下发钥匙管理
                String msg_89 = "aa1b890000000100013132333435363132333431323334" + EslcsSocketUtcUtil.getNowDateBCD() + "303132333400";
                ctx.channel().writeAndFlush(
                    EslcsSocketHexUtil.HexToByteArr(msg_89 + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_89))
                        + EslcsSocketConstants.Constants_endIndex));
                LOGGER.error("--------Netty Service " + ctx.channel().id().asShortText() + " " + msg_89
                    + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_89)) + EslcsSocketConstants.Constants_endIndex + "---------");
            } else if (EslcsSocketConstants.Constants_89.equals(cmdValue)) {
                if (count_89 == 0) {
                    String msg_89 = "AA0a890000000101ffffffffffffffffffff";
                    ctx.channel().writeAndFlush(
                        EslcsSocketHexUtil.HexToByteArr(msg_89 + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_89))
                            + EslcsSocketConstants.Constants_endIndex));
                    LOGGER.error("--------Netty Service " + ctx.channel().id().asShortText() + " " + msg_89
                        + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_89)) + EslcsSocketConstants.Constants_endIndex + "---------");
                }
                count_89++;
            } else if (EslcsSocketConstants.Constants_80.equals(cmdValue) || EslcsSocketConstants.Constants_81.equals(cmdValue)) {// 开 -关
                if (!str.toUpperCase().equals("AA0A800000000100FFFFFFFFFFFFFFFFFFFF2155")) {
                    analyseDate(channelId, EslcsSocketConstants.Constants_80, eEffData, effDataLength);
                }
                String msg_8081 = EslcsSocketConstants.Constants_beginIndex + "01" + cmdValue + cmdValueId + "0100";
                ctx.channel().writeAndFlush(
                    EslcsSocketHexUtil.HexToByteArr(msg_8081 + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_8081))
                        + EslcsSocketConstants.Constants_endIndex));
                LOGGER.error("--------Netty Service " + ctx.channel().id().asShortText() + " " + msg_8081
                    + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_8081)) + EslcsSocketConstants.Constants_endIndex + "---------");
                if (str.toUpperCase().equals("AA0A800000000100FFFFFFFFFFFFFFFFFFFF2155")) {
                    ctx.close();
                }
                
            }
        } else {
            // 校验失败
            LOGGER
                .error("-------------------------Netty xor error,命令字：" + ctx.channel().id().asShortText() + " " + cmdValue + "--------------------");
            switch (cmdValue) {
                case EslcsSocketConstants.Constants_70:
                    String msg_70 = "aa0170000000010001";
                    ctx.channel().writeAndFlush(
                        EslcsSocketHexUtil.HexToByteArr(msg_70 + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_70))
                            + EslcsSocketConstants.Constants_endIndex));
                    break;
                case EslcsSocketConstants.Constants_25:
                    String msg_25 = "aa0125000000010101";
                    ctx.channel().writeAndFlush(
                        EslcsSocketHexUtil.HexToByteArr(msg_25 + EslcsSocketHexUtil.Byte2Hex(EslcsSocketHexUtil.xor(msg_25))
                            + EslcsSocketConstants.Constants_endIndex));
                    break;
                case EslcsSocketConstants.Constants_89:
                    ctx.channel().writeAndFlush("13");
                    break;
                case EslcsSocketConstants.Constants_80:// 开
                    String str_80 = EslcsSocketConstants.Constants_beginIndex + "01" + cmdValue + cmdValueId + "0101";
                    ctx.channel().writeAndFlush(
                        EslcsSocketHexUtil.HexToByteArr(str_80 + EslcsSocketHexUtil.xorBy16(str_80) + EslcsSocketConstants.Constants_endIndex));
                    break;
                case EslcsSocketConstants.Constants_81:// 关
                    String str_81 = EslcsSocketConstants.Constants_beginIndex + "01" + cmdValue + cmdValueId + "0102";
                    ctx.channel().writeAndFlush(
                        EslcsSocketHexUtil.HexToByteArr(str_81 + EslcsSocketHexUtil.xorBy16(str_81) + EslcsSocketConstants.Constants_endIndex));
                    break;
            }
        }
        
    }
    
    private String analyseDate(String channelId, String cmdValue, String eEffData, String effDataLength) {
        String msg = "";
        int eEffDataLength = eEffData.length() / 2;
        int length = EslcsSocketHexUtil.HexToInt(effDataLength);
        int size = eEffDataLength / length;
        int beginIndex = 0;
        int endIndex = length * 2;
        List<EslcsLockLogDTO> eslcsLockLogDTOs = new ArrayList<EslcsLockLogDTO>();
        for (int i = 0; i < size; i++) {
            EslcsLockLogDTO eslcsLockLogDTO = new EslcsLockLogDTO();
            String eEffDataStr = eEffData.substring(beginIndex, endIndex);
            String[] hexToStringArr = EslcsSocketHexUtil.HexToStringArr(eEffDataStr);
            if (EslcsSocketConstants.Constants_80.equals(cmdValue) || EslcsSocketConstants.Constants_81.equals(cmdValue)) {// 开 -关
                String lockId = new String(EslcsSocketHexUtil.HexToByteArr(EslcsSocketHexUtil.subStr(hexToStringArr, 0, 6)));
                eslcsLockLogDTO.setLockId(lockId);
                eslcsLockLogDTO.setUnlockingTime(EslcsSocketUtcUtil.convertFromUTCSeconds(EslcsSocketHexUtil.HexToInt(EslcsSocketHexUtil.subStr(
                    hexToStringArr, 6, 10))));
                eslcsLockLogDTO.setUpdateTime(new Timestamp(new Date().getTime()));
                if (null != keyMap.get(channelId)) {
                    EslcsKeyDTO eslcsKeyDTO = eslcsKeyFacade.queryById(keyMap.get(channelId).getKey().split(" ")[3]);
                    if (null != eslcsKeyDTO) {
                        eslcsLockLogDTO.setUnlockingUserName(eslcsKeyDTO.getPossessorName());
                        eslcsLockLogDTO.setUnlockingKey(eslcsKeyDTO.getKeyCode());
                    }
                }
                eslcsLockLogDTOs.add(eslcsLockLogDTO);
            }
            beginIndex = endIndex;
            endIndex += (length * 2);
        }
        if (EslcsSocketConstants.Constants_80.equals(cmdValue) || EslcsSocketConstants.Constants_81.equals(cmdValue)) {
            eslcsLockLogFacade.batchCreate(eslcsLockLogDTOs);
        }
        return msg;
    }
    
    private String getMessage(ByteBuf buf) {
        byte[] con = new byte[buf.readableBytes()];
        buf.readBytes(con);
        return new String(con, StandardCharsets.UTF_8);
    }
    
}
